package com.goodomen.garbage.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.DeflateDecompressingEntity;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

@SuppressWarnings("deprecation")
public class HttpUtils {
	
	private final static Logger LOG = LoggerFactory.getLogger(HttpUtils.class);
	
	public final static String GB2312 = "GB2312";
	public final static String UTF_8 = "UTF-8";
	
	private final static int CONNECTION_TIMEOUT = 10000;
	private final static int SO_TIMEOUT = 10000;

	/**
	 * 代理访问,随机遍历代理服务器
	 * @param proxyList
	 * @param url
	 * @return
	 */
	public static RequestResult proxyRequest(List<ProxyServer> proxyList, String url) {
		RequestResult result = null;
		while (!proxyList.isEmpty()) {
			int i = (int) (Math.random() * proxyList.size());
			ProxyServer proxyServer = proxyList.get(i);
			try {
				result = proxyRequest(proxyServer, url);
			} catch (Exception e) {
				if(LOG.isWarnEnabled()){
					LOG.warn("httpclient is error!", e.getMessage());
				}
			}
			if (result!=null&&StringUtils.isNotEmpty(result.getContent())) {
				return result;
			}
			proxyList.remove(i);
		}
		// 显示结果
		return result;
	}
	
	/**
	 * 代理访问
	 * @param proxyServer
	 * @param url
	 * @return
	 */
	public static RequestResult proxyRequest(ProxyServer proxyServer, String url) throws Exception {
		DefaultHttpClient httpClient = null;
		try {
			int index1 = url.indexOf("//") + 2;
			int index2 = url.lastIndexOf("/");
			String host = "";
			String postfix = "";
			if(index2>index1){
				host = url.substring(url.indexOf("//") + 2, url.lastIndexOf("/"));
				postfix = url.substring(url.lastIndexOf("/"), url.length());
			}else{
				host = url;
			}
			httpClient = new DefaultHttpClient();
			httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);
			httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
			
			httpClient.getCredentialsProvider().setCredentials(
					new AuthScope(proxyServer.getIp(), proxyServer.getPort()),
					new UsernamePasswordCredentials("", "")); // 128.8.126.11 3124
			HttpHost targetHost = new HttpHost(host);
			
			HttpHost proxy = new HttpHost(proxyServer.getIp(), proxyServer.getPort()); // 这两句话去掉就是直接访问不用代理
			httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,proxy);
			HttpGet httpGet = new HttpGet(postfix);
			addCommonHeader(httpGet);
			HttpResponse response = httpClient.execute(targetHost, httpGet);
			RequestResult result = reponse(url, response, UTF_8);
			httpGet.abort();
			return result;
		} catch (Exception e) {
			if(LOG.isWarnEnabled()){
				LOG.warn("httpclient is error! proxyServer:" + proxyServer.getIp() + ":" + proxyServer.getPort(), e.getMessage());
			}
		} finally {
			if(httpClient != null) {
				httpClient.getConnectionManager().shutdown();
			}
		}
		return null;
	}
	
	/**
	 * 直接访问
	 * @param url
	 * @return
	 */
	public static RequestResult httpRequest(String url) {
		return httpRequest(url, UTF_8);
	}
	
	/**
	 * 直接访问
	 * @param url
	 * @param charset
	 * @return
	 */
	public static RequestResult httpRequest(String url, String charset) {
		DefaultHttpClient httpClient = null;
		try {
			httpClient = new DefaultHttpClient();
			httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
			httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000);
			
			HttpGet httpGet = new HttpGet(url);
			addCommonHeader(httpGet);
			HttpResponse response = httpClient.execute(httpGet);
			RequestResult result = reponse(url, response, charset);
			httpGet.abort();
			return result;
		} catch (Exception e) {
			if(LOG.isWarnEnabled()){
				LOG.warn("httpclient is error!", e.getMessage());
			}
		} finally {
			if(httpClient != null) {
				httpClient.getConnectionManager().shutdown();
			}
		}
		return null;
	}
	
	/**
	 * 请求json数据
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static RequestResult jsoupRequest(String url) throws Exception {
		RequestResult result = new RequestResult();
		String content = Jsoup.parse(new URL(url), 1000*10).html();
		if("".equals(content)){
			content = null;
		}
		result.setContent(content);
		return result;
	}
	
	/**
	 * POST 请求
	 * @param url
	 * @param params
	 * @param charset
	 * @return
	 */
	public static String postRequest(String url, HashMap<String, String> params, String charset) {
		return postRequest(url, params, charset, "");
	}

	/**
	 * POST 请求
	 * @param url
	 * @param params
	 * @param charset
	 * @return
	 */
	public static String postRequest(String url, HashMap<String, String> params, String charset, String split) {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SO_TIMEOUT)
				.setConnectTimeout(CONNECTION_TIMEOUT).build(); // 设置请求和传输超时时间
		HttpPost httppost = null;
		try {
		    httppost = new HttpPost(url);
			httppost.setConfig(requestConfig);
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			if (params != null) {
				Iterator<String> it = params.keySet().iterator();
				while (it.hasNext()) {
					String key = it.next();
					nvps.add(new BasicNameValuePair(key, params.get(key)));
				}
			}
			httppost.setEntity(new UrlEncodedFormEntity(nvps, charset));
			HttpResponse response = httpclient.execute(httppost);

			HttpEntity resEntity = response.getEntity();
			StringBuffer buffer = new StringBuffer();
			if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
				InputStream instream = resEntity.getContent();
				BufferedReader reader = new BufferedReader(new InputStreamReader(instream, charset));
				String line = "";
				while ((line = reader.readLine()) != null) {
					buffer.append(line + split);
				}
				return buffer.toString();
			}
		} catch (Exception e) {
			LOG.error("http post request is error!", e);
		} finally {
			try {
				httppost.abort();
				httpclient.close();
			} catch (IOException e) {
			
			}
		}
		return null;
	}

	/**
	 * 测试代理服务器是否可用
	 * @param ip			代理服务器的网址
	 * @param port			代理服务器的端口
	 * @param username		用户名
	 * @param password 		密码
	 * @param targetUrl		目标url
	 * @return
	 */
	public static boolean testProxy(String ip, int port, String username, String password, String targetUrl) {
		if(username == null){
			username = "";
		}
		if(password == null){
			password = "";
		}
		boolean result = false;
		DefaultHttpClient httpClient = null;
		try {
			int index1 = targetUrl.indexOf("//") + 2;
			int index2 = targetUrl.lastIndexOf("/");
			String host = "";
			String postfix = "";
			if(index2>index1){
				host = targetUrl.substring(targetUrl.indexOf("//") + 2, targetUrl.lastIndexOf("/"));
				postfix = targetUrl.substring(targetUrl.lastIndexOf("/"), targetUrl.length());
			}else{
				host = targetUrl;
			}
			httpClient = new DefaultHttpClient();
			httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);
			httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
			
			httpClient.getCredentialsProvider().setCredentials(
					new AuthScope(ip, port),
					new UsernamePasswordCredentials(username, password));
			HttpHost targetHost = new HttpHost(host);
			
			HttpHost proxy = new HttpHost(ip, port); // 这两句话去掉就是直接访问不用代理
			httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,proxy);
			HttpGet httpGet = new HttpGet(postfix);
			addCommonHeader(httpGet);
			HttpResponse response = httpClient.execute(targetHost, httpGet);
			
			if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {// 成功返回
				result = true;
			}
			httpGet.abort();
		} catch (Exception e) {
			if(LOG.isWarnEnabled()){
				LOG.warn("http client is error! proxy server:" + ip + ":" + port, e.getMessage());
			}
		} finally {
			if(httpClient != null) {
				httpClient.getConnectionManager().shutdown();
			}
		}
		return result;
	}
	
	/**
	 * 封装http请求结果
	 * @param url
	 * @param response
	 * @return
	 * @throws Exception
	 */
	private static RequestResult reponse(String url, HttpResponse response, String charset) throws Exception {
		RequestResult result = new RequestResult();
		result.setReturnCode(response.getStatusLine().getStatusCode());
		if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {// 成功返回
			HttpEntity entity = response.getEntity();
			result.setContentType(entity.getContentType().getValue());
			
			String encoding = entity.getContentEncoding() != null && entity.getContentEncoding().getValue() != null ? entity.getContentEncoding().getValue() : "";
			if (encoding.equalsIgnoreCase("GZIP")) {
				entity = new GzipDecompressingEntity(entity);
			} else if (encoding.equalsIgnoreCase("DEFLATE")) {
				entity = new DeflateDecompressingEntity(entity);
			}
			charset = charset == null ? UTF_8 : charset;
			String content = EntityUtils.toString(entity, charset);
			Document doc = Jsoup.parse(content);
			Elements eles = doc.select("meta[http-equiv=Content-Type]");
			if (eles != null && !eles.isEmpty()) {
				Element e = eles.get(0);
				String v = e.attr("content");
				String set;
				if (v.indexOf("charset") > -1) {
					set = v.substring(v.indexOf("=") + 1, v.length());
				} else {
					Elements eles0 = doc.select("meta[charset]");
					Element e0 = eles0.get(0);
					set = e0.attr("charset");
				}
				if (!charset.equalsIgnoreCase(set)) {
					content = httpRequest(url, set).getContent();
				}
			} else {
				LOG.warn("not has char set, url:" + url);
			}
			result.setContent(content);
			EntityUtils.consume(entity);
		} else {
			LOG.warn("visit url:{}, return code:{}", url, response.getStatusLine().getStatusCode());
		}
		return result;
	}
	
	/**
	 * 添加http header
	 */
	private static void addCommonHeader(HttpRequest httpRequest) {
		httpRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36");
		httpRequest.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		httpRequest.addHeader("Accept-Language", "zh-CN,zh;q=0.8");
		httpRequest.addHeader("Accept-Encoding", "gzip, deflate, sdch");
		httpRequest.addHeader("Cache-Control", "max-age=0");
	}
	
	/**
	 * 代理配置
	 */
	public static class ProxyServer implements Serializable {
		
		private static final long serialVersionUID = -525917817890014727L;
		
		private String  ip;			// ip
	    private int port;			// 端口
	    private String username;	// 登录名
		private String password;	// 登录密码
		
		public ProxyServer(String ip, int port, String username, String password){
			this.ip = ip;
			this.port = port;
			this.username = username;
			this.password = password;
		}

		public String getIp() {
			return ip;
		}

		public int getPort() {
			return port;
		}

		public String getUsername() {
			return username;
		}

		public String getPassword() {
			return password;
		}

	}
	
	/**
	 * http请求结果
	 */
	public static class RequestResult {
		
		private String content; // 返回内容
		private int returnCode; // 返回码
		private byte[] stream; //用于返回二进制文件。如图像。
		private String contentType;
		
		public String getContentType() {
			return contentType;
		}

		public void setContentType(String contentType) {
			this.contentType = contentType;
		}

		public byte[] getStream() {
			return stream;
		}

		public void setStream(byte[] stream) {
			this.stream = stream;
		}

		public String getContent() {
			return content;
		}

		public void setContent(String content) {
			this.content = content;
		}

		public int getReturnCode() {
			return returnCode;
		}

		public void setReturnCode(int returnCode) {
			this.returnCode = returnCode;
		}

		public boolean isBinaryStream() {
			// FIXME:暂时只添加image的支持
			return contentType != null && contentType.startsWith("image");
		}
	}
}
